package ig.metrica.liquidez;

import ig.metrica.riesgo.ZonaDTO;
import java.rmi.RemoteException;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;

import javax.ejb.FinderException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import ig.finanzas.AccionPK;
import ig.finanzas.Banda;
import ig.finanzas.Contrato;
import ig.finanzas.ContratoPK;
import ig.finanzas.ContratoSimpleHome;
import ig.finanzas.Flujo;
import ig.finanzas.ManejadorBandas;
import ig.finanzas.ManejadorFlujos;
import ig.finanzas.Moneda;
import ig.finanzas.MonedaHome;
import ig.finanzas.MonedaPK;
import ig.finanzas.PosicionAccion;
import ig.finanzas.PosicionAccionHome;
import ig.finanzas.PosicionEspecieHome;
import ig.metrica.ejb.html.GenerarHTML;
import ig.util.ConexionServer;
import ig.util.ejb.IGSessionBean;
import ig.util.excepciones.DatoInvalidoExcepcion;
import ig.util.excepciones.LogicaExcepcion;

public class CalculoLiquidezBean extends IGSessionBean implements CalculoLiquidezBussines {
    private GenerarHTML generarHTML=null;
    private InitialContext _ctx_ = null;
    private Collection<ZonaDTO> collection=new ArrayList();
    public void setGenerarHTML(GenerarHTML generarHTML) {
        this.generarHTML = generarHTML;
    }
    private MonedaHome monedaHome = null;
    public void ejbCreate(){}
    
    private Moneda getMoneda(MonedaPK monedaPK) throws NamingException, FinderException{
        try {
            if(monedaHome==null){
                if(_ctx_==null){
                    Properties prop = new Properties();
                    prop.put( Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
                    String Sockec = new ConexionServer().getSocketServer();
                    prop.put( Context.PROVIDER_URL, Sockec);
                    _ctx_ = new InitialContext(prop);
                }
                monedaHome  = (MonedaHome)_ctx_.lookup("ig.finanzas.Moneda");
            }
            return monedaHome .findByPrimaryKey(monedaPK);
        } catch (RemoteException e) {
            throw new FinderException(e.getMessage());
        }
    }
    
    /**
     * Efectua el analisis de liquidez.
     * @param fecha
     * @param confPeriodos La definicion de los periodos es del tipo: 30, 60, 145, 180,. etc.
     * @param comportamientoAcciones
     * @throws DatoInvalidoExcepcion Si la fecha o el comportamiento para las acciones es nulo,
     * o si alguno de los datos de la configuracion de los periodos de una banda es 0,
     * o si un dato de la confifurancion de los periodods es menor a su inmediatamente anterior,
     * o si no hay suficiente informacion para determinar el valor de la moneda a una fecha,
     * o si no existe suficiente informacion para valorar las acciones a una determinada fecha.
     * @throws SQLException Si se presento un error al conectarse u obtener los datos de la base de datos.
     * @throws NamingException Si se presento un error con JNDI.
     * @throws FinderException Si no se pueden encontrar los objetos en el servidor de aplicaciones.
     */
    public void efectuarCalculo(Date fecha, ManejadorBandas bandas, Hashtable comportamientoAcciones)
    throws DatoInvalidoExcepcion, LogicaExcepcion, NamingException, SQLException, FinderException{
        
        if (fecha==null)
            throw new DatoInvalidoExcepcion("La fecha especificada para el analisis es nula.");
        
        if (comportamientoAcciones==null){
            comportamientoAcciones= new Hashtable();
            //	throw new DatoInvalidoExcepcion("No existes definiciones del calculo sobre las acciones.");
        }
        
        Properties prop = new Properties();
        prop.put( Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
        String Sockec = new ConexionServer().getSocketServer();
        prop.put( Context.PROVIDER_URL, Sockec);
        
        Iterator i, j, k;
        Collection contratos;
        
        try {
            conn = getConexion("METRICADB");
            
            //Se borra la informacion de las tablas donde se va a almacenar la informacion.
            Statement stmt1 = conn.createStatement();
            stmt1.executeUpdate("DELETE FROM FLUJOSLIQUIDEZ");
            stmt1.executeUpdate("DELETE FROM BANDASLIQUIDEZ");
            if (stmt1!=null)
                stmt1.close();
            
            //Se crean las bandas
            //ManejadorBandas bandas = ManejadorBandas.crearBandas(fecha, confPeriodos);            
            //System.out.println("BANDAS:"+bandas);
            
            pstmt1 = conn.prepareStatement("INSERT INTO BANDASLIQUIDEZ VALUES(?,?,?) ");
            int contador = 0;
            i = bandas.getColeccionBandas().iterator();
            while(i.hasNext()){
                Banda banda = (Banda)i.next();
                generarHTML.println("Bandas : "+banda.getFechaInicio()+" & "+banda.getFechaFin());
                
                contador++;
                pstmt1.setInt( 1, contador );
                pstmt1.setDate(2, new java.sql.Date(banda.getFechaInicio().getTime()));
                if (banda.getFechaFin()!=null)
                    pstmt1.setDate(3, new java.sql.Date(banda.getFechaFin().getTime()));
                else
                    pstmt1.setDate(3, null);
                pstmt1.executeUpdate();
                banda.setIdInterna(contador);
            }
            
            InitialContext _ctx = new InitialContext(prop);
            
            pstmt1 = conn.prepareStatement("INSERT INTO FLUJOSLIQUIDEZ VALUES(?, ?, ?, ?, ?, ?, ?)");
            
            contador = 0;
            
            /*
             * ---------------------------------------------------------------------------------------------------------------------
             * Para cada contrato simple y posicion en el sistema extraigo los flujos que caen en cada una de las bandas
             * especificadas y convierto sus valores a pesos para ser guardados.
             */
            //System.out.println("a");
            ContratoSimpleHome home1 = (ContratoSimpleHome)_ctx.lookup("ig.finanzas.ContratoSimple");
            //System.out.println("b");
            PosicionEspecieHome home2 = (PosicionEspecieHome)_ctx.lookup("ig.finanzas.PosicionEspecie");
            //System.out.println("c");
            contratos = home1.findAll();
            contratos.addAll( home2.findAll() );
            generarHTML.setLineasDeEspera(0);
//            generarHTML.println("Guardando Flujos Liquidez");
//            generarHTML.println("Procesando "+contratos.size()+" entre ContratoSimple y PosicionEspecie");
//            generarHTML.println("Procesando Bandas liquidez");
            i = contratos.iterator();
            while (i.hasNext()){
                //Recorriendo los ContratosSimples
                Object obj=i.next();
                //System.out.println("obj:"+obj.getClass().getName());
                Contrato contrato = (Contrato)obj;
                MonedaPK monedaPK = contrato.getMonedaPK();
                Moneda moneda = getMoneda(monedaPK);
                double cambio = moneda.obtenerValorVigenteA(fecha);
                
                j = bandas.getColeccionBandas().iterator();

                while(j.hasNext()){
                    
                    //Recorriendo las Bandas
                    Object obj1=j.next();
                    Banda banda = (Banda)obj1;
                    ManejadorFlujos flujos = contrato.flujosEntre( banda.getFechaInicio(), false, banda.getFechaFin(), true );
                    k = flujos.getColeccionFlujos().iterator();
                    while(k.hasNext()){
                        
                        //Recorriendo los flujos dentro de una banda
                        Flujo flujo = (Flujo)k.next();
                        contador++;
                        pstmt1.setInt( 1, contador );
                        pstmt1.setDouble(2, flujo.getCapital()*cambio);
                        pstmt1.setDouble(3, flujo.getInteresFijo()*cambio);
                        pstmt1.setDouble(4, flujo.getInteresVariable()*cambio);
                        pstmt1.setDate(5, new java.sql.Date(flujo.getFecha().getTime()));
                        pstmt1.setLong(6, banda.getIdInterna());
                        pstmt1.setLong(7, ((ContratoPK)contrato.getPrimaryKey()).getIdInterna() );
                        pstmt1.executeUpdate();
                    }
                }
            }
            
                        /*
                         * ------------------------------------------------------------------------------------------------------------------
                         * Para el caso de contratos de posiciones de acciones se adicionan flujos
                         * dependiendo de la fecha donde se desee realizar la liquidacion de los
                         * mismos.
                         */
            
            PosicionAccionHome home3 = (PosicionAccionHome)_ctx.lookup("ig.finanzas.PosicionAccion");
//            new PosicionAccionBean().ejbFindAll();
            contratos = home3.findAll();
            i = contratos.iterator();
//            generarHTML.println("Procesando "+contratos.size()+" PosicionAccion");
            while (i.hasNext()){
                
                //Recorriendo los contratos.
                PosicionAccion contrato = (PosicionAccion)i.next();
                MonedaPK monedaPK = contrato.getMonedaPK();
                Moneda moneda = getMoneda(monedaPK);
                AccionPK accionPK = contrato.getAccionPK();
                
                if ( comportamientoAcciones.containsKey(accionPK) ){
                    
                    //Si hay comportamiento definido para este tipo de accion
                    GregorianCalendar gc = new GregorianCalendar();
                    gc.setTime(fecha);
                    gc.add(Calendar.DATE, ((Integer)comportamientoAcciones.get(accionPK)).intValue() );
                    Date fechaFlujo = gc.getTime();
                    
                    Banda banda = (Banda)bandas.getRango(fecha);
                    double cambio = moneda.obtenerValorVigenteA(fecha);
                    
                    contador++;
                    pstmt1.setInt(1, contador);
                    pstmt1.setDouble(2, contrato.valorar(fecha)*cambio);
                    pstmt1.setDouble(3, 0);
                    pstmt1.setDouble(4, 0);
                    pstmt1.setDate(5, new java.sql.Date(fechaFlujo.getTime()));
                    pstmt1.setLong(6, banda.getIdInterna());
                    pstmt1.setLong(7, ((ContratoPK)contrato.getPrimaryKey()).getIdInterna() );
                    pstmt1.executeUpdate();
                }
            }
//            generarHTML.println("Bandas liquidez - ok");
        } catch (RemoteException e) {
            e.printStackTrace();
            //generarHTML.println("Error al tratar de calcular la Liquidez");
            throw new DatoInvalidoExcepcion(e.getMessage());
            
        } finally{
            try {
                if (pstmt1!=null) pstmt1.close();
            } catch (SQLException e) {e.printStackTrace();}
            
            try {
                if (conn!=null) conn.close();
            } catch (SQLException e) {e.printStackTrace();}
        }
        
    }

    public void setZonas(Collection<ZonaDTO> collection) {
        this.collection=collection;
    }
    
}
